﻿{
	UCE - cross-platform game engine written in delphi.
	Copyright (c) 2009, Shutko Vitaly

	This file is part of UCE.

	UCE is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	UCE is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the Free Software
	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
}

unit uGfxGL;

interface

uses
{$IFDEF WIN32}
  Windows,
{$ELSE}
  glx,
{$ENDIF}
  uOpenGL, uTyp, uGfx;

type
  TGfxGL = class(TGfx)
  {$IFDEF WIN32}
    dc, rc: Cardinal;
    pfd: TPixelFormatDescriptor;
  {$ELSE}
  	cont: TGLXContext;
  {$ENDIF}

    exts: record
      str: String;
      texBorderClamp: Boolean;
    end;

    function Init: Boolean; override;
    procedure SetCanvasSize; override;
    procedure BeginFrame; override;
    procedure EndFrame; override;
    procedure PushTrans; override;
    procedure PopTrans; override;
    procedure Trans(x, y: Single); override;
    procedure Rotate(angle: Single); override;
    procedure Scale(x, y: Single); override;
    procedure DrawPrim(type_, count: Integer; verts: Pointer); override;
    procedure NoTex; override;

    constructor Create;
    destructor Destroy; override;
  end;

implementation

uses
  uVar
{$IFDEF WIN32}
  , uAppWin32
{$ELSE}
  , uAppLinux
{$ENDIF}
  ;

constructor TGfxGL.Create;
begin
{$IFDEF WIN32}
  dc := 0;
  rc := 0;
{$ENDIF}
end;

destructor TGfxGL.Destroy;
begin
{$IFDEF WIN32}
  if rc <> 0 then
  begin
    wglMakeCurrent(dc, 0);
    wglDeleteContext(rc);
  end;

  if dc <> 0 then ReleaseDC(0, 0);
{$ELSE}
	if cont <> nil then glXDestroyContext(TAppLinux(app).disp, cont);
{$ENDIF}
end;

function TGfxGL.Init: Boolean;
begin
  Result := False;

  if not InitOpenGL then
  begin
    con.Msg('# Не удается загрузить библиотеку OpenGL');
    Exit;
  end;

{$IFDEF WIN32}
  dc := GetDC(TAppWin32(app).wnd);

  if dc = 0 then
  begin
    //error
    Exit;
  end;

  FillChar(pfd, SizeOf(pfd), 0);

  with pfd do
  begin
    nSize := SizeOf(pfd);
    nVersion := 1;
    dwFlags := PFD_DOUBLEBUFFER or PFD_DRAW_TO_WINDOW or PFD_SUPPORT_OPENGL;
    iPixelType := PFD_TYPE_RGBA;
    cColorBits := eng.conf.bpp;
  end;

  if not SetPixelFormat(dc, ChoosePixelFormat(dc, @pfd), @pfd) then
  begin
    //error
    Exit;
  end;

  rc := wglCreateContext(dc);

  if rc = 0 then
  begin
    //error
    Exit;
  end;

  if not wglMakeCurrent(dc, rc) then
  begin
    //error
    Exit;
  end;
{$ELSE}
	cont := glXCreateContext(TAppLinux(app).disp, TAppLinux(app).vi, nil, True);

  if cont = nil then
  begin
  	//error
    Exit;
  end;

  if not glXMakeCurrent(TAppLinux(app).disp, TAppLinux(app).wnd, cont) then
  begin
    //error
    Exit;
  end;
{$ENDIF}

  exts.str := glGetString(GL_EXTENSIONS);

  with exts do
  begin
    exts.texBorderClamp := Pos('SGIS_texture_border_clamp', exts.str) <> 0;
  end;

  glClearColor(0,0,0,0);
  glColor4ub(255,255,255,255);
  glEnable(GL_TEXTURE_2D);
  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

  Result := True;
end;

procedure TGfxGL.SetCanvasSize;
begin
  glMatrixMode(GL_PROJECTION);
  glPushMatrix;
  glLoadIdentity;
  glOrtho(0, eng.conf.cw, eng.conf.ch, 0, -100, 100);
  glMatrixMode(GL_MODELVIEW);
end;

procedure TGfxGL.BeginFrame;
begin
  glClear(GL_COLOR_BUFFER_BIT);
  glLoadIdentity;
end;

procedure TGfxGL.EndFrame;
begin
  glFlush;

{$IFDEF WIN32}
  SwapBuffers(dc);
{$ELSE}
  glXSwapBuffers(TAppLinux(app).disp, TAppLinux(app).wnd);
{$ENDIF}
end;

procedure TGfxGL.PushTrans;
begin
  glPushMatrix;
end;

procedure TGfxGL.PopTrans;
begin
  glPopMatrix;
end;

procedure TGfxGL.Trans(x, y: Single);
begin
  glTranslatef(x, y, 0);
end;

procedure TGfxGL.Rotate(angle: Single);
begin
  if angle <> 0 then
    glRotatef(angle, 0, 0, 1);
end;

procedure TGfxGL.Scale(x, y: Single);
begin
  glScalef(x, y, 1);
end;

procedure TGfxGL.DrawPrim(type_, count: Integer; verts: Pointer);
var
  i: Integer;
  p, c: Cardinal;
begin
  case type_ of
    GFX_LINES: begin p := GL_LINES; c := 2 * count; end;
    GFX_LINESTRIP: begin p := GL_LINE_STRIP; c := 1 + count; end;
    GFX_TRIFAN: begin p := GL_TRIANGLE_FAN; c := 2 + count; end;
    else Exit;
  end;

  glBegin(p);

  for i := 0 to c - 1 do
    with PGfxVert(Pointer(Integer(verts) + i * SizeOf(TGfxVert)))^ do
    begin
      glColor4ub(color.b, color.g, color.r, color.a);
      glTexCoord2f(u, v);
      glVertex2f(x, y);
    end;

  glEnd;
end;

procedure TGfxGL.NoTex;
begin
  glBindTexture(GL_TEXTURE_2D, 0);
end;

end.
